package com.lvcoding.auth2.auth.shizhan.config;

import com.lvcoding.auth2.auth.shizhan.filter.ValidateCodeFilter;
import com.lvcoding.auth2.auth.shizhan.grant.CustomAuthenticationProvider;
import com.lvcoding.auth2.auth.shizhan.security.CustomAccessDeniedHandler;
import com.lvcoding.auth2.auth.shizhan.security.CustomDaoAuthenticationProvider;
import com.lvcoding.auth2.auth.shizhan.security.CustomAuthenticationEntryPoint;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Order(2) // 资源服务器的默认 @Order 值为 3，这就是示例将 Web 的 @Order 设置为 2 的原因，以便更早地对其进行评估
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
    private final CustomAccessDeniedHandler customAccessDeniedHandler;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/h2-console/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter();
        // http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);

        http
                // requestMatchers这个方法是用于限定只有特定的HttpServletRequest实例才会导致该HttpSecurity被调用，当然是通过请求uri进行限定的了。它后面可以接多个匹配规则。
                // .requestMatchers()
                // .antMatchers("/oauth/authorize", "/login/**") // 这些uri会让HttpSecurity被调用
                // .and()
                .authorizeRequests()
                .antMatchers("/h2-console/**", "/user/**", "/code/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .and()
                .exceptionHandling(exceptionHandlingConfigurer -> {
                    exceptionHandlingConfigurer.authenticationEntryPoint(customAuthenticationEntryPoint)
                            .accessDeniedHandler(customAccessDeniedHandler);

                })
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .csrf().disable();
    }

    @Bean
    public CustomDaoAuthenticationProvider daoAuthenticationProvider() throws Exception {
        CustomDaoAuthenticationProvider provider = new CustomDaoAuthenticationProvider();
        provider.setPasswordEncoder(passwordEncoder());
        return provider;
    }

    @Bean
    public CustomAuthenticationProvider customAuthenticationProvider() throws Exception {
        CustomAuthenticationProvider provider = new CustomAuthenticationProvider();
        provider.setPasswordEncoder(passwordEncoder());
        return provider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 用户名密码授权提供者
        auth.authenticationProvider(daoAuthenticationProvider());
        // 自定义授权提供者
        auth.authenticationProvider(customAuthenticationProvider());
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
